package it.uiip.crm.persistenza;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

/**
 * Basato su HibernateUtil di Gavin King e Christian Bauer
 */
public class PersistenceManager {
    private static Log log = LogFactory.getLog(PersistenceManager.class);
    
    private static SessionFactory sessionFactory;
    private static final ThreadLocal threadSession = new ThreadLocal();
    private static final ThreadLocal threadTransaction = new ThreadLocal();
    
    static {
        try {
            Configuration configuration = new Configuration();
            sessionFactory = configuration.configure().buildSessionFactory();
        } catch (Throwable ex) {
            log.error("Building SessionFactory failed.", ex);
            throw new ExceptionInInitializerError(ex);
        }
    }
    
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
    
    public static Session getSession()  {
        Session s = (Session) threadSession.get();
        if (s == null) {
            log.debug("Opening new Session for this thread.");
            s = getSessionFactory().openSession();
            threadSession.set(s);
        }
        return s;
    }

    public static void refreshObject(Object obj)  {
        Session s = (Session) threadSession.get();
        s.refresh(obj);
    }
    
    public static void closeSession() {
        Session s = (Session) threadSession.get();
        threadSession.set(null);
        if (s != null && s.isOpen()) {
            log.debug("Closing Session of this thread.");
            s.close();
        }
    }
    
    public static void beginTransaction() throws DAOException {
        Transaction transaction = (Transaction) threadTransaction.get();
        try {
            if (transaction == null) {
                log.debug("Starting new database transaction in this thread.");
                transaction = getSession().beginTransaction();
                threadTransaction.set(transaction);
            }
        } catch (HibernateException ex) {
            throw new DAOException(ex);
        }
    }
    
    public static void commitTransaction() throws DAOException {
        Transaction transaction = (Transaction) threadTransaction.get();
        try {
            if (transaction != null && !transaction.wasCommitted() && !transaction.wasRolledBack() ) {
                log.debug("Committing database transaction of this thread.");
                transaction.commit();
            }
            threadTransaction.set(null);
        } catch (HibernateException ex) {
            rollbackTransaction();
            throw new DAOException(ex);
        } finally {
            
        }
    }
    
    public static void rollbackTransaction() throws DAOException {
        Transaction transaction = (Transaction) threadTransaction.get();
        try {
            threadTransaction.set(null);
            if (transaction != null && !transaction.wasCommitted() && !transaction.wasRolledBack() ) {
                log.debug("Tyring to rollback database transaction of this thread.");
                transaction.rollback();
            }
        } catch (HibernateException ex) {
            throw new DAOException(ex);
        } finally {
            closeSession();
        }
    }
}
